Lightkurve quicklook prototype

This version of the notebook is trying to incorporate short cadence data into the same widget by limiting the range of values plotted at one time.

In [1]:
%matplotlib notebook
from lightkurve import KeplerTargetPixelFile
import numpy as np

Let’s make the Jupyter cells wider

In [2]:
from IPython.core.display import display, HTML
display(HTML("<style>.container { width:100% !important; }</style>"))

Download a Kepler target pixel file (TPF)

In [3]:
#tpf = KeplerTargetPixelFile.from_archive('210698281', campaign=13)
tpf = KeplerTargetPixelFile.from_archive('249914869', campaign=15, cadence='short')
tpf.flux.shape
Downloading URL https://mast.stsci.edu/api/v0/download/file?uri=mast:K2/url/missions/k2/target_pixel_files/c15/249900000/14000/ktwo249914869-c15_spd-targ.fits.gz to ./mastDownload/K2/ktwo249914869-c15_sc/ktwo249914869-c15_spd-targ.fits.gz ... [Done]
Out[3]:
(127288, 9, 10)

Define a new interact routine including pixel selection for the mask

In [4]:
def interact(tpf, rmin=None, rmax=None, lc=None):
    """
    Interact with a linked target pixel file and lightcurve

    Parameters
    ----------
    rmin : an optional minimum time index for initial light curve. Defaults to 0 if not supplied by user.
    rmax : an optional maximum time index for initial light curve. Defaults to 3000 if not supplied by user. Note that
    rmax - rmin should not be more than ~10,000 for quicker plotting
    lc : an optional user-supplied pre-processed lightcurve for this target


    Returns
    -------
    ax : matplotlib.axes._subplots.AxesSubplot
        The matplotlib axes object.
    """

    lc = tpf.to_lightcurve()
    try:
        from ipywidgets import interact
        import ipywidgets as widgets
        from bokeh.io import push_notebook, show, output_notebook
        from bokeh.plotting import figure, ColumnDataSource
        from bokeh.models import Span
        from bokeh.models import LogColorMapper
        from bokeh.layouts import row, column
        from bokeh.themes import Theme
        from bokeh.models.tools import HoverTool, PointDrawTool
        from bokeh.models.widgets import Button
        output_notebook()
    except ImportError:
        raise ImportError('The quicklook tool requires Bokeh and ipywidgets.  See the Installation Guide.')

    if lc is None:
        lc = tpf.to_lightcurve()

    if rmin is None:
        rmin = 0

    if rmax is None:
        rmax = 3000

    source = ColumnDataSource(data=dict(
        time=lc.time, flux=lc.flux,
        cadence=lc.cadenceno,
        quality=lc.quality))

    def update(f, v, r):
        vert.update(location=tpf.time[f])
        s2_dat.data_source.data['image'] = [tpf.flux[f,:,:]]
        s2_dat.glyph.color_mapper.high = v[1]
        s2_dat.glyph.color_mapper.low = v[0]
        steps.data_source.data.update(time=lc.time[r[0]:r[1]],
                                      flux=lc.flux[r[0]:r[1]],
                                      cadence=lc.cadenceno[r[0]:r[1]],
                                      quality=lc.quality[r[0]:r[1]])
        push_notebook()

    title = "Quicklook lightcurve for {} target {}".format(tpf.mission, tpf.keplerid)
    p = figure(title=title, plot_height=300, plot_width=600, tools="tap,pan,wheel_zoom,box_zoom,reset")#, theme=theme)
    p.yaxis.axis_label = 'Normalized Flux'
    p.xaxis.axis_label = 'Time - 2454833 (days)'
    steps = p.step('time', 'flux', line_width=1, color='gray', source=source, nonselection_line_color='gray')
    #p.step(cuttime, cutflux, line_width=1, color='gray', source=source, nonselection_line_color='gray')

    r = p.circle('time', 'flux', source=source, fill_alpha=0.3, size=8,line_color=None,
    #r = p.circle(cuttime, cutflux, source=source, fill_alpha=0.3, size=8,line_color=None,
                 selection_color="firebrick", nonselection_fill_alpha=0.0,
                 nonselection_fill_color="grey",nonselection_line_color=None,
                 nonselection_line_alpha=0.0, fill_color=None,
                 hover_fill_color="firebrick",hover_alpha=0.9,hover_line_color="white")

    p.add_tools(HoverTool(tooltips=[("index", "$index"),
                                    ("cadence", "@cadence"),
                                    ("time", "@time{0,0.000}"),
                                    ("flux", "@flux"),
                                    ("quality", "@quality")],
                          renderers=[r], mode='mouse', point_policy="snap_to_data"))

    vert = Span(location=800, dimension='height', line_color='firebrick', line_width=4, line_alpha=0.5)
    p.add_layout(vert)
    s2 = figure(plot_width=300, plot_height=300, title='Target Pixel File', tools='tap, box_zoom, reset')
    s2.yaxis.axis_label = 'Pixel Row Number'
    s2.xaxis.axis_label = 'Pixel Column Number'

    pedestal = np.nanmin(tpf.flux)
    vlo, lo, med, hi, vhi = np.fix(np.nanpercentile(tpf.flux-pedestal, [0.2, 1, 50, 95, 99.8]))
    color_mapper = LogColorMapper(palette="Viridis256", low=lo, high=hi)

    s2_dat = s2.image([pedestal+tpf.flux[0,:,:]], x=tpf.column, y=tpf.row,
                      dw=tpf.shape[2], dh=tpf.shape[1], dilate=True,
                      color_mapper=color_mapper)

    source2 = ColumnDataSource(data=dict(xx=x_vals+0.5, yy=y_vals+0.5))
    r1 = s2.rect('xx', 'yy', 1, 1, source=source2, fill_color='gray', fill_alpha=0.4, line_color='white')
    ptool = PointDrawTool(renderers=[r1])
    s2.add_tools(ptool)
    s2.toolbar.active_tap = ptool

    #button = Button(label="Foo", button_type="success")
    #def my_button_handler(new):
    #    print('Button option ' + str(new) + ' selected.')

    #button.on_click(my_button_handler)




    show(row(p, s2), notebook_handle=True)
    n_cad, nx, ny = tpf.flux.shape

    play = widgets.Play(
        interval=10,
        value=9,
        min=0,
        max=n_cad-1,
        step=1,
        description="Press play",
        disabled=False)

    #wbutton = widgets.Button(
    #    description='Click me',
    #    disabled=False,
    #    button_style='', # 'success', 'info', 'warning', 'danger' or ''
    #    icon='check')


    #def on_button_clicked(b):
    #    bool_mask = tpf.pipeline_mask*False
    #    for xi, yi in zip(r1.data_source.data['xx'], r1.data_source.data['yy']):
    #        xc = np.int(np.round(xi-0.5)-tpf.column)
    #        yc = np.int(np.round(yi-0.5)-tpf.row)
    #        bool_mask[xc, yc] = True
    #        print(xc, yc)
    #    source.data['flux'] = tpf.to_lightcurve(aperture_mask=bool_mask).flux
    #    print('click', bool_mask.sum())

    #wbutton.on_click(on_button_clicked)
    style = {'description_width': 'initial'}

    f_slider = widgets.IntSlider(min=0,max=n_cad-1,step=1,value=5,
                                 layout=widgets.Layout(width='40%', height='20px'),
                                 description="Pixel file plotted:", style=style)

    r_slider = widgets.IntRangeSlider(value=[rmin,rmax], min=0,max=n_cad-1,step=1,
                                 layout=widgets.Layout(width='80%', height='20px'),
                                      description="Light curve range:", style=style)

    vstep = np.round((hi-lo)/300.0, 1)

    v_slider = widgets.FloatRangeSlider(value=[lo, hi],
                                        min=0,
                                        max=hi,
                                        step=vstep,
                                        description='v:',
                                        continuous_update=False,
                                        layout=widgets.Layout(width='30%', height='20px'))

    widgets.jslink((play, 'value'), (f_slider, 'value'))

    ui = widgets.VBox([widgets.HBox([r_slider]),widgets.HBox([play, f_slider, v_slider])])
    out = widgets.interactive_output(update, {'f': f_slider, 'v':v_slider, 'r':r_slider})
    display(ui, out)
    return p

Define where the pixels are for this particular target pixel file

In [5]:
xx=tpf.column + np.arange(tpf.shape[2])
yy=tpf.row + np.arange(tpf.shape[1])
In [6]:
x, y = np.meshgrid(xx, yy)
In [7]:
x_vals, y_vals = x[tpf.pipeline_mask], y[tpf.pipeline_mask]

Test the new interact tools

Delete pixel boxes by while clicking the box, then press ‘delete’ while your cursor is still hovering over the image.

In [8]:
out = interact(tpf)
Loading BokehJS ...
In [ ]:

Below this is stuff for cleaning lightcurves…

In [ ]:
lc_sff = lc_cln.correct(restore_trend=True)
In [16]:
lc_cln = my_custom_lc_cleaner(tpf, cleaning='best')
In [15]:
def my_custom_lc_cleaner(tpf, cleaning='best'):
    '''Returns a clean lightcurve given an input tpf'''

    nan_mask = np.all(np.isnan(tpf.flux), axis=0)
    empty_mask = tpf.pipeline_mask * False
    aper_mask = empty_mask
    aper_mask[1:-1, 1:-1] = True
    back_mask = ~aper_mask & ~nan_mask

    lc_aper = tpf.to_lightcurve(aperture_mask=aper_mask)/aper_mask.sum()
    lc_back = tpf.to_lightcurve(aperture_mask=back_mask)/back_mask.sum()

    lc_bg_sub = lc_aper - lc_back.flux

    # Flag outliers
    _, outliers1 = lc_aper.remove_outliers(return_mask=True)
    _, outliers2 = lc_back.remove_outliers(return_mask=True)

    _, outliers3 = lc_aper.flatten().remove_outliers(return_mask=True)

    outlier_dict= {'none': outliers1*False,
                   'safe':(tpf.quality > 0.0),
                   'soft': outliers1,
                   'medium':(outliers1 | outliers2),
                   'best': (outliers1 | outliers2 | (tpf.quality > 0.0)),
                   'aggressive':(outliers1 | outliers2 | (tpf.quality > 0.0) | outliers3)}

    outliers = outlier_dict[cleaning]

    lc_cln = lc_bg_sub[~outliers]

    return lc_cln
In [ ]:
lc_cln = my_custom_lc_cleaner(tpf, cleaning='best')
In [ ]:

In [ ]: